package top.lixunda.ecommerce.server.good.service.impl;

import com.alipay.api.AlipayApiException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import top.lixunda.commerce.common.core.entity.MessageObject;
import top.lixunda.common.utils.ObjectValidators;
import top.lixunda.common.utils.alipay.AlipayClientUtils;
import top.lixunda.common.utils.alipay.constant.TradeStatus;
import top.lixunda.common.utils.alipay.entity.AlipayDefaultParam;
import top.lixunda.common.utils.alipay.entity.AlipayNotifyResult;
import top.lixunda.ecommerce.server.business.BaseConvertServiceImpl;
import top.lixunda.ecommerce.server.business.api.entity.cache.CacheStore;
import top.lixunda.ecommerce.server.business.api.entity.cache.CacheStoreUser;
import top.lixunda.ecommerce.server.business.api.entity.cache.CacheUser;
import top.lixunda.ecommerce.server.business.api.entity.dto.PageConvertDTO;
import top.lixunda.ecommerce.server.business.api.entity.dto.PageConvertWrapperDTO;
import top.lixunda.ecommerce.server.good.api.entity.db.*;
import top.lixunda.ecommerce.server.good.api.entity.dto.AdminOrderDetailQueryDTO;
import top.lixunda.ecommerce.server.good.api.entity.dto.GoodOrderInsertDTO;
import top.lixunda.ecommerce.server.good.api.entity.dto.OrderDetailQueryDTO;
import top.lixunda.ecommerce.server.good.api.entity.dto.StoreOrderDetailQueryDTO;
import top.lixunda.ecommerce.server.good.api.entity.vo.OrderConvertVO;
import top.lixunda.ecommerce.server.good.mapper.*;
import top.lixunda.ecommerce.server.good.service.IGoodOrderService;
import top.lixunda.ecommerce.server.good.service.IOrderDetailService;
import top.lixunda.ecommerce.server.user.api.entity.db.UserAddressDO;
import top.lixunda.ecommerce.server.user.api.feign.IFeignUserAddressController;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * VIEW 服务实现类
 * </p>
 *
 * @author Xumda
 * @since 2019-12-18
 */
@Slf4j
@Service
public class OrderDetailServiceImpl
        extends BaseConvertServiceImpl<OrderDetailMapper, OrderDetailDO,
        GoodOrderServiceImpl, GoodOrderMapper, GoodOrderDO, OrderConvertVO>
        implements IOrderDetailService {

    private final GoodOrderMapper goodOrderMapper;

    private final IGoodOrderService goodOrderService;

    private final SubOrderMapper subOrderMapper;

    private final GoodsMapper goodsMapper;

    private final SubGoodMapper subGoodMapper;

    private final AlipayNotifyMapper alipayNotifyMapper;

    private final OrderApplyMapper orderApplyMapper;

    private final IFeignUserAddressController feignUserAddressController;

    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    public OrderDetailServiceImpl(GoodOrderMapper goodOrderMapper,
                                  IGoodOrderService goodOrderService,
                                  SubOrderMapper subOrderMapper,
                                  GoodsMapper goodsMapper,
                                  SubGoodMapper subGoodMapper,
                                  AlipayNotifyMapper alipayNotifyMapper,
                                  OrderApplyMapper orderApplyMapper,
                                  IFeignUserAddressController feignUserAddressController) {
        super(OrderConvertVO::fromOrderDetailDO, GoodOrderDO::getId, OrderDetailDO::getOrderId);
        this.goodOrderMapper = goodOrderMapper;
        this.goodOrderService = goodOrderService;
        this.subOrderMapper = subOrderMapper;
        this.goodsMapper = goodsMapper;
        this.subGoodMapper = subGoodMapper;
        this.alipayNotifyMapper = alipayNotifyMapper;
        this.orderApplyMapper = orderApplyMapper;
        this.feignUserAddressController = feignUserAddressController;
    }

    /**
     * 根据id查询订单数据，只能查询当前登陆账户的订单
     *
     * @param ids 订单id
     * @return 订单列表
     */
    @Override
    public List<OrderConvertVO> queryOrderDetailByIds(List<Integer> ids) {
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("订单id不能为空");
        }
        CacheUser userInfoDO = currentUserCacheNotNull();

        LambdaQueryWrapper<OrderDetailDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderDetailDO::getUserId, userInfoDO.getAccount())
                .eq(OrderDetailDO::getUserFlag, GoodOrderDO.FLAG_TRUE);
        if (ids.size() == 1) {
            wrapper.eq(OrderDetailDO::getOrderId, ids.get(0));
        } else {
            wrapper.in(OrderDetailDO::getOrderId, ids);
        }
        List<OrderConvertVO> list = this.listConvert(wrapper);
        if (list == null) {
            log.info("获取订单数据失败，返回值list为空");
            throw getAppException("获取订单数据失败");
        }

        return list;
    }

    /**
     * 分页条件查询订单数据，只能查询当前登陆账户的订单数据
     *
     * @param pageDTO 分页数据和提哦啊见数据
     * @return 订单数据列表
     */
    @Override
    public IPage<OrderConvertVO> queryOrderDetailPageWrapper(
            PageConvertDTO<GoodOrderDO, OrderDetailDO, OrderDetailQueryDTO> pageDTO) {
        if (pageDTO == null) {
            throw getAppException("分页信息不能为空");
        }
        CacheUser userInfoDO = currentUserCacheNotNull();
        PageConvertWrapperDTO<GoodOrderDO, OrderDetailDO, OrderConvertVO>
                pageConvertWrapperDTO = new PageConvertWrapperDTO<>();
        pageConvertWrapperDTO.setPage(pageDTO.getPage())
                .setPageWrapper(pageDTO.getPageWrapper(
                        wrapper -> wrapper.eq(GoodOrderDO::getUserId, userInfoDO.getAccount())
                                .eq(GoodOrderDO::getUserFlag, GoodOrderDO.FLAG_TRUE)))
                .setQueryWrapper(pageDTO.getQueryWrapper());
        return this.pageConvert(pageConvertWrapperDTO);
    }

    /**
     * 店铺调用，根据订单id查看多个订单信息，但api可以查看本人的所有订单, 默认根据时间排序
     *
     * @param ids 订单id
     * @return 订单详细数据
     */
    @Override
    public List<OrderConvertVO> queryOrderDetailByIdsStore(List<Integer> ids) {
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("订单id不能为空");
        }
        CacheStore cacheStore = currentStoreCacheNotNull();

        LambdaQueryWrapper<OrderDetailDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderDetailDO::getStoreId, cacheStore.getId())
                .eq(OrderDetailDO::getStoreFlag, GoodOrderDO.FLAG_TRUE);
        if (ids.size() == 1) {
            wrapper.eq(OrderDetailDO::getOrderId, ids.get(0));
        } else {
            wrapper.in(OrderDetailDO::getOrderId, ids);
        }
        List<OrderConvertVO> list = this.listConvert(wrapper);
        if (list == null) {
            log.info("获取订单数据失败，返回值list为空");
            throw getAppException("获取订单数据失败");
        }

        return list;
    }

    /**
     * 店铺调用，分页条件查询
     *
     * @param pageDTO 分页数据和提哦啊见数据
     * @return 订单详细数据列表
     */
    @Override
    public IPage<OrderConvertVO> queryOrderDetailPageWrapperStore(
            PageConvertDTO<GoodOrderDO, OrderDetailDO, StoreOrderDetailQueryDTO> pageDTO) {
        if (pageDTO == null) {
            throw getAppException("分页信息不能为空");
        }
        CacheStore cacheStore = currentStoreCacheNotNull();
        PageConvertWrapperDTO<GoodOrderDO, OrderDetailDO, OrderConvertVO> pageConvertWrapperDTO = new PageConvertWrapperDTO<>();
        pageConvertWrapperDTO.setPage(pageDTO.getPage())
                .setPageWrapper(pageDTO.getPageWrapper(
                        wrapper -> wrapper.eq(GoodOrderDO::getStoreId, cacheStore.getId())
                                .eq(GoodOrderDO::getStoreFlag, GoodOrderDO.FLAG_TRUE)))
                .setQueryWrapper(pageDTO.getQueryWrapper());
        return this.pageConvert(pageConvertWrapperDTO);
    }

    /**
     * 管理员调用，根据订单id查看多个订单信息，但api可以查看本人的所有订单, 默认根据时间排序
     *
     * @param ids 订单id
     * @return 订单详细数据
     */
    @Override
    public List<OrderConvertVO> queryOrderDetailByIdsAdmin(List<Integer> ids) {
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("订单id不能为空");
        }
        LambdaQueryWrapper<OrderDetailDO> wrapper = new LambdaQueryWrapper<>();
        if (ids.size() == 1) {
            wrapper.eq(OrderDetailDO::getOrderId, ids.get(0));
        } else {
            wrapper.in(OrderDetailDO::getOrderId, ids);
        }
        List<OrderConvertVO> list = this.listConvert(wrapper);
        if (list == null) {
            log.info("获取订单数据失败，返回值list为空");
            throw getAppException("获取订单数据失败");
        }

        return list;
    }

    /**
     * 管理员调用，分页条件查询
     *
     * @param pageDTO 分页数据和提哦啊见数据
     * @return 订单详细数据列表
     */
    @Override
    public IPage<OrderConvertVO> queryOrderDetailPageWrapperAdmin(
            PageConvertDTO<GoodOrderDO, OrderDetailDO, AdminOrderDetailQueryDTO> pageDTO) {
        if (pageDTO == null) {
            throw getAppException("分页信息不能为空");
        }
        PageConvertWrapperDTO<GoodOrderDO, OrderDetailDO, OrderConvertVO> pageConvertWrapperDTO = new PageConvertWrapperDTO<>();
        pageConvertWrapperDTO.setPage(pageDTO.getPage())
                .setPageWrapper(pageDTO.getPageWrapper())
                .setQueryWrapper(pageDTO.getQueryWrapper());
        return this.pageConvert(pageConvertWrapperDTO);
    }

    /**
     * 用户调用，根据id删除订单
     *
     * @param ids 订单id列表
     * @return 是否删除成功
     */
    @Override
    public Boolean removeOrderByIds(List<Integer> ids) {
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("参数不能为空");
        }
        CacheUser userInfoDO = currentUserCacheNotNull();
        GoodOrderDO updateEntity = new GoodOrderDO();
        updateEntity.setUserFlag(GoodOrderDO.FLAG_FALSE);
        int success = goodOrderMapper.update(updateEntity,
                new LambdaUpdateWrapper<GoodOrderDO>()
                        .set(GoodOrderDO::getUserFlag, GoodOrderDO.FLAG_FALSE)
                        .eq(GoodOrderDO::getUserId, userInfoDO.getAccount())
                        .in(GoodOrderDO::getId, ids)
                        .eq(GoodOrderDO::getUserFlag, GoodOrderDO.FLAG_TRUE));
        if (success <= 0) {
            throw getAppException("移除订单信息失败");
        }
        return true;
    }

    /**
     * 店家调用，根据id删除订单
     *
     * @param ids 订单id列表
     * @return 是否删除成功
     */
    @Override
    public Boolean removeOrderByIdsStore(List<Integer> ids) {
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("参数不能为空");
        }
        CacheStoreUser cacheStoreUser = currentStoreUserCacheNotNull();
        GoodOrderDO updateEntity = new GoodOrderDO();
        updateEntity.setStoreFlag(GoodOrderDO.FLAG_FALSE);
        int success = goodOrderMapper.update(updateEntity,
                new LambdaUpdateWrapper<GoodOrderDO>()
                        .set(GoodOrderDO::getStoreFlag, GoodOrderDO.FLAG_FALSE)
                        .eq(GoodOrderDO::getStoreId, cacheStoreUser.getAccount())
                        .in(GoodOrderDO::getId, ids)
                        .eq(GoodOrderDO::getUserFlag, GoodOrderDO.FLAG_TRUE));
        if (success <= 0) {
            throw getAppException("移除订单信息失败");
        }
        return true;
    }

    /**
     * 生成用于插入的GoodOrderDO数据
     *
     * @param goodOrderInsertDTO DTO
     * @param goodsDO            GoodsDO
     * @param subGoodDO          SubGoodDO
     * @return GoodOrderDO
     */
    private GoodOrderDO initGoodOrderDO(GoodOrderInsertDTO goodOrderInsertDTO,
                                        GoodsDO goodsDO, SubGoodDO subGoodDO, UserAddressDO userAddressDO) {
        GoodOrderDO goodOrderDO = new GoodOrderDO();
        LocalDateTime localDateTime = LocalDateTime.now();
        CacheUser userInfoDO = currentUserCacheNotNull();
        goodOrderDO.setUserId(userInfoDO.getAccount());
        goodOrderDO.setUserName(userInfoDO.getFirstName() + userInfoDO.getLastName());
        goodOrderDO.setStoreId(goodsDO.getStoreId());
        goodOrderDO.setStoreName(goodsDO.getStoreName());
        goodOrderDO.setCreateTime(localDateTime);
        // 商品总价 = 商品单价 * 商品数量
        BigDecimal allPrice = subGoodDO.getPrice().multiply(BigDecimal.valueOf(goodOrderInsertDTO.getCount()));
        goodOrderDO.setGoodsPrice(allPrice);
        goodOrderDO.setFreight(goodsDO.getFreight());
        goodOrderDO.setHaveFreightInsu(0);
        goodOrderDO.setFreightInsu(BigDecimal.ZERO);
        goodOrderDO.setRedEnvelope(BigDecimal.ZERO);
        // 实付价格 = 商品总价 + 运费 + 运险费 - 红包减免
        BigDecimal truePrice = goodOrderDO.getGoodsPrice().add(goodOrderDO.getFreight())
                .add(goodOrderDO.getFreightInsu()).subtract(goodOrderDO.getRedEnvelope());
        goodOrderDO.setPrice(truePrice);
        // 积分 = (实付价格 / 10) 向上舍入取整
        goodOrderDO.setIntegral(truePrice.divide(BigDecimal.valueOf(10), 0, RoundingMode.UP).intValue());
        goodOrderDO.setEndAddressId(userAddressDO.getId());
        goodOrderDO.setEndAddressDesc(userAddressDO.toString());
        goodOrderDO.setState(GoodOrderDO.STATE_TO_PAY);
        goodOrderDO.setMessage(goodOrderInsertDTO.getMessage());
        return goodOrderDO;
    }

    /**
     * 生成用于插入的SubOrderDO数据
     *
     * @param goodOrderInsertDTO DTO
     * @param goodOrderDO        插入成功的订单数据
     * @param goodsDO            GoodsDO
     * @param subGoodDO          SubGoodDO
     * @return SubOrderDO
     */
    private SubOrderDO initSubOrderDO(GoodOrderInsertDTO goodOrderInsertDTO,
                                      GoodOrderDO goodOrderDO,
                                      GoodsDO goodsDO, SubGoodDO subGoodDO) {
        SubOrderDO subOrderDO = new SubOrderDO();
        subOrderDO.setOrderId(goodOrderDO.getId());
        subOrderDO.setGoodId(goodsDO.getId());
        subOrderDO.setGoodName(goodsDO.getName());
        subOrderDO.setSubGoodId(subGoodDO.getId());
        subOrderDO.setSubGoodName(subGoodDO.getSubGoodName());
        subOrderDO.setPrice(subGoodDO.getPrice());
        subOrderDO.setCount(goodOrderInsertDTO.getCount());
        // 商品总价 = 商品单价 * 数量
        subOrderDO.setTotal(subOrderDO.getPrice().multiply(
                BigDecimal.valueOf(goodOrderInsertDTO.getCount())));
        subOrderDO.setFreight(goodsDO.getFreight());
        // 积分 = (实付价格 / 10) 向上舍入取整
        subOrderDO.setIntegral(subOrderDO.getTotal()
                .divide(BigDecimal.valueOf(10), 0, RoundingMode.UP).intValue());
        return subOrderDO;
    }

    /**
     * 直接购买商品，生成订单
     *
     * @param goodOrderInsertDTO DTO
     * @return OrderConvertVO
     */
    @Override
    @Transactional(isolation = Isolation.REPEATABLE_READ, rollbackFor = Exception.class)
    public OrderConvertVO insertGoodOrderDTO(GoodOrderInsertDTO goodOrderInsertDTO) {
        if (ObjectValidators.isEmpty(goodOrderInsertDTO)) {
            throw getAppException("参数不能为空");
        }
        // 获取子商品数据
        SubGoodDO subGoodDO = subGoodMapper.selectOne(
                new LambdaQueryWrapper<SubGoodDO>()
                        .eq(SubGoodDO::getId, goodOrderInsertDTO.getSubGoodId())
                        .eq(SubGoodDO::getState, SubGoodDO.STATE_NORMAL)
        );
        if (ObjectValidators.isEmpty(subGoodDO)) {
            log.debug("子商品不存在");
            throw getAppException("商品不存在");
        }
        // 获取商品数据
        GoodsDO goodsDO = goodsMapper.selectOne(
                new LambdaQueryWrapper<GoodsDO>()
                        .eq(GoodsDO::getId, subGoodDO.getGoodId())
                        .eq(GoodsDO::getState, GoodsDO.STATE_NORMAL)
        );
        if (ObjectValidators.isEmpty(goodsDO)) {
            log.debug("主商品不存在");
            throw getAppException("商品不存在");
        }
        // 获取地址数据
        log.debug("123123 : {}", goodOrderInsertDTO);
        MessageObject<UserAddressDO> messageObject =
                feignUserAddressController.queryAddressById(goodOrderInsertDTO.getAddressId());
        if (ObjectValidators.isEmpty(messageObject)
                || messageObject.getCode() != MessageObject.CODE_OK
                || ObjectValidators.isEmpty(messageObject.getObject())) {
            throw getAppException("获取用户地址数据失败");
        }
        if (subGoodDO.getCount() < goodOrderInsertDTO.getCount()) {
            throw getAppException("商品数量不足");
        }
        // 扣减商品数量
        int count = subGoodDO.getCount() - goodOrderInsertDTO.getCount();
        subGoodDO.setCount(count);
        int success = subGoodMapper.update(subGoodDO, new LambdaUpdateWrapper<SubGoodDO>()
                .eq(SubGoodDO::getId, subGoodDO.getId())
                .set(SubGoodDO::getCount, count));
        if (success < 0) {
            throw getAppException("扣减商品失败");
        }
        //插入订单数据
        GoodOrderDO goodOrderDO = initGoodOrderDO(
                goodOrderInsertDTO, goodsDO, subGoodDO, messageObject.getObject());
        success = goodOrderMapper.insert(goodOrderDO);
        if (success <= 0) {
            throw getAppException("插入订单数据失败");
        }

        SubOrderDO subOrderDO = initSubOrderDO(goodOrderInsertDTO, goodOrderDO, goodsDO, subGoodDO);
        success = subOrderMapper.insert(subOrderDO);
        if (success <= 0) {
            throw getAppException("插入订单数据失败");
        }

        // 查询数据返回
        return this.getConvertById(String.valueOf(goodOrderDO.getId()));
    }

    /**
     * 根据id取消订单
     *
     * @param ids 取消订单的订单编号
     * @return 取消的订单数据
     */
    @Override
    public List<OrderConvertVO> cancelOrderByIds(List<Integer> ids) {
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("订单编号不能为空");
        }
        CacheUser userInfoDO = currentUserCacheNotNull();
        List<GoodOrderDO> list = goodOrderMapper.selectList(new LambdaQueryWrapper<GoodOrderDO>()
                .in(GoodOrderDO::getId, ids)
                .eq(GoodOrderDO::getUserId, userInfoDO.getAccount())
                .eq(GoodOrderDO::getState, GoodOrderDO.STATE_TO_PAY));
        if (ObjectValidators.isEmpty(list)) {
            throw getAppException("订单不存在或不能取消");
        }
        List<Integer> newIds = list.stream()
                .map(GoodOrderDO::getId)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        if (ObjectValidators.isEmpty(newIds)) {
            throw getAppException("订单不存在或不能取消");
        }
        LocalDateTime localDateTime = LocalDateTime.now();
        boolean success = goodOrderService.update(new LambdaUpdateWrapper<GoodOrderDO>()
                .set(GoodOrderDO::getEndTime, localDateTime)
                .set(GoodOrderDO::getState, GoodOrderDO.STATE_CANCEL)
                .in(GoodOrderDO::getId, newIds)
                .eq(GoodOrderDO::getUserId, userInfoDO.getAccount())
                .eq(GoodOrderDO::getState, GoodOrderDO.STATE_TO_PAY));
        if (!success) {
            throw getAppException("更新数据失败");
        }
        // 返还商品库存
        this.rollbackOrderGoodsCountByIds(newIds);

        return this.listConvertByIds(newIds.stream()
                .map(String::valueOf)
                .collect(Collectors.toList()));
    }

    /**
     * 返回订单中的库存
     *
     * @param list 订单详细信息
     */
    private void rollbackOrderGoodsCount(List<OrderDetailDO> list) {
        if (ObjectValidators.isEmpty(list)) {
            throw getAppException("返回订单商品库存失败！参数订单数据不能为空！");
        }
        // 转换子商品id
        List<Integer> subGoodIdList = list.stream()
                .map(OrderDetailDO::getSubGoodId)
                .collect(Collectors.toList());
        // 查询子商品库存数量
        List<SubGoodDO> subGoodList = subGoodMapper.selectList(
                new LambdaQueryWrapper<SubGoodDO>()
                        .in(SubGoodDO::getId, subGoodIdList)
                        .select(SubGoodDO::getId, SubGoodDO::getCount));
        // 转换Map，方便获取
        Map<Integer, SubGoodDO> subGoodMap = subGoodList.stream()
                .collect(Collectors.toMap(SubGoodDO::getId, item -> item));
        // 更改子商品库存
        list.forEach(item -> {
            SubGoodDO subGoodDO = subGoodMap.get(item.getSubGoodId());
            if (ObjectValidators.isEmpty(subGoodDO)) {
                throw getAppException("返回订单商品库存失败！子商品不存在！");
            }
            subGoodDO.setCount(subGoodDO.getCount() + item.getSubCount());
        });
        // 修改数据，返还商品库存
        subGoodList.forEach(subGoodMapper::updateById);
    }

    /**
     * 返回订单中的库存
     *
     * @param orderIds 订单编号列表
     */
    private void rollbackOrderGoodsCountByIds(List<Integer> orderIds) {
        if (ObjectValidators.isEmpty(orderIds)) {
            throw getAppException("返回订单商品库存失败！订单编号列表不能为空！");
        }
        List<OrderDetailDO> list = this.list(new LambdaQueryWrapper<OrderDetailDO>()
                .in(OrderDetailDO::getOrderId, orderIds));
        if (ObjectValidators.isEmpty(list)) {
            throw getAppException("返回订单商品库存失败！订单数据为空！");
        }
        this.rollbackOrderGoodsCount(list);
    }

    /**
     * 购买商品并前往支付
     *
     * @param returnUrl 支付返回地址
     * @param goodOrderInsertDTO DTO
     * @return String 页面html
     */
    @Override
    @Transactional(isolation = Isolation.REPEATABLE_READ, rollbackFor = Exception.class)
    public String buyGoodToOrderPage(String returnUrl, GoodOrderInsertDTO goodOrderInsertDTO) {
        //1. 插入订单
        OrderConvertVO orderConvertVO = insertGoodOrderDTO(goodOrderInsertDTO);
        //2. 前往支付
        return toPayOrderPage(returnUrl, orderConvertVO);
    }

    /**
     * 对本地订单进行支付
     *
     * @param orderId 订单id
     * @param returnUrl 支付返回地址
     * @return 返回页面html
     */
    @Override
    public String toPayOrderPage(int orderId, String returnUrl) {
        if (ObjectValidators.isEmpty(orderId)) {
            throw getAppException("订单编号不能为空");
        }
        CacheUser userInfoDO = currentUserCacheNotNull();
        List<OrderConvertVO> list = this.listConvert(new LambdaQueryWrapper<OrderDetailDO>()
                .eq(OrderDetailDO::getOrderId, orderId)
                .eq(OrderDetailDO::getUserId, userInfoDO.getAccount())
        );
        if (ObjectValidators.isEmpty(list)) {
            throw getAppException("商品订单不存在");
        }
        return toPayOrderPage(returnUrl, list.get(0));
    }

    /**
     * 对本地订单进行支付
     *
     * @param returnUrl 支付返回地址
     * @param orderConvertVO 订单数据
     * @return 返回页面html
     */
    @Override
    public String toPayOrderPage(String returnUrl, OrderConvertVO orderConvertVO) {
        if (ObjectValidators.isEmpty(orderConvertVO)) {
            throw getAppException("系统错误,订单数据不能为空");
        }
        if (ObjectValidators.isEmpty(orderConvertVO.getState())
                || !GoodOrderDO.STATE_TO_PAY.equals(orderConvertVO.getState())) {
            throw getAppException("不能支付的订单");
        }
        CacheUser userInfoDO = currentUserCacheNotNull();
        AlipayDefaultParam alipayDefaultParam = new AlipayDefaultParam();
        List<SubOrderDO> list = orderConvertVO.getList();
        if (ObjectValidators.isEmpty(list)) {
            log.error("订单商品为空");
            throw getAppException("系统错误,订单数据不能为空");
        }
        final StringBuilder subjectBuilder = new StringBuilder();
        final StringBuilder bodyBuilder = new StringBuilder();
        list.forEach(item -> {
            if (subjectBuilder.length() > 0) {
                subjectBuilder.append("|");
            }
            if (bodyBuilder.length() > 0) {
                bodyBuilder.append("|");
            }
            subjectBuilder.append(item.getGoodName());
            bodyBuilder.append(item.getGoodName())
                    .append("|")
                    .append(item.getSubGoodName());
        });
        alipayDefaultParam.setSubject(subjectBuilder.toString());
        alipayDefaultParam.setBody(bodyBuilder.toString());
        alipayDefaultParam.setOutTradeNo(String.valueOf(orderConvertVO.getId()));
        alipayDefaultParam.setTotalAmount(String.valueOf(orderConvertVO.getPrice()));
        String param = "userId%" + userInfoDO.getAccount() + "%orderId%" + orderConvertVO.getId();
        alipayDefaultParam.setPassbackParams(param);
        alipayDefaultParam.setReturnUrl(returnUrl);

        return AlipayClientUtils.toPay(alipayDefaultParam);
    }

    /**
     * 订单支付回调
     *
     * @param map 数据
     * @param request HttpServletRequest
     * @return 错误信息
     */
    @Override
    public String payOrderNotifyCallback(Map<String, String> map, HttpServletRequest request) {
        if (ObjectValidators.isEmpty(map)) {
            log.error("支付回调参数为空");
            return ("支付回调参数为空");
        }
        try {
            if (!AlipayClientUtils.rsaCheckV1(request)) {
                log.error("支付回调校验失败");
                return "支付回调校验失败";
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        String tradeStatus = map.get("trade_status");
        if (ObjectValidators.isEmpty(tradeStatus) || !TradeStatus.TRADE_SUCCESS.equals(tradeStatus)) {
            log.error("支付失败");
            return ("支付失败");
        }
        String param = map.get("passback_params");
        if (ObjectValidators.isEmpty(param)) {
            log.error("自定义回调参数为空");
            return ("系统错误，联系管理员");
        }
        String[] params = param.split("%");
        Map<String, String> paramMap = new HashMap<>(8);
        for (int i = 0; i < params.length; i += 2) {
            paramMap.put(params[i], params[i + 1]);
        }
        String userId = paramMap.get("userId");
        String orderId = paramMap.get("orderId");
        if (ObjectValidators.isEmpty(userId) || ObjectValidators.isEmpty(orderId)) {
            log.error("自定义回调参数缺失");
            return ("系统错误，联系管理员");
        }

        // 保存记录数据
        AlipayNotifyDO alipayNotifyDO = AlipayNotifyDO.fromMap(
                map, Integer.parseInt(userId), Integer.parseInt(orderId));
        alipayNotifyMapper.insert(alipayNotifyDO);

        GoodOrderDO goodOrderDO = new GoodOrderDO();
        goodOrderDO.setId(Integer.parseInt(orderId));
        goodOrderDO.setState(GoodOrderDO.STATE_TO_TRANS);
        goodOrderDO.setPriceTime(LocalDateTime.now());
        goodOrderDO.setPayType(GoodOrderDO.PAY_TYPE_ALI_PAY);
        goodOrderDO.setPayId(alipayNotifyDO.getTradeNo());
        goodOrderMapper.update(goodOrderDO, new LambdaUpdateWrapper<GoodOrderDO>()
                .eq(GoodOrderDO::getUserId, Integer.parseInt(userId))
                .eq(GoodOrderDO::getId, Integer.parseInt(orderId))
                .eq(GoodOrderDO::getState, GoodOrderDO.STATE_TO_PAY));
        return "";
    }

    /**
     * 用户调用，申请退款，申请后由店家验证退款
     *
     * @param orderId 订单编号
     * @param message 申请理由
     * @return 是否申请成功
     */
    @Override
    public Boolean applyRefundByOrderId(Integer orderId, String message) {
        if (ObjectValidators.isEmpty(orderId)) {
            throw getAppException("订单编号不能为空");
        }
        CacheUser userInfoDO = currentUserCacheNotNull();
        GoodOrderDO goodOrderDO = goodOrderMapper.selectOne(
                new LambdaQueryWrapper<GoodOrderDO>()
                        .eq(GoodOrderDO::getId, orderId)
                        .eq(GoodOrderDO::getState, GoodOrderDO.STATE_TO_TRANS)
                        .eq(GoodOrderDO::getUserId, userInfoDO.getAccount()));
        if (ObjectValidators.isEmpty(goodOrderDO) || ObjectValidators.isEmpty(goodOrderDO.getId())) {
            throw getAppException("订单不存在或权限不足");
        }
        // 修改订单状态
        goodOrderDO.setState(GoodOrderDO.STATE_TO_REFUND);
        int count = goodOrderMapper.updateById(goodOrderDO);
        if (count <= 0) {
            log.error("修改订单状态失败");
            throw getAppException("修改订单状态失败");
        }
        // 插入订单事件
        OrderApplyDO orderApplyDO = new OrderApplyDO();
        orderApplyDO.setOrderId(goodOrderDO.getId())
                .setEventType(OrderApplyDO.EVENT_TYPE_REFUND)
                .setMessage(message)
                .setCreateUserId(userInfoDO.getAccount())
                .setCreateUserName(userInfoDO.getFirstName() + " " + userInfoDO.getLastName())
                .setCreateTime(LocalDateTime.now());
        count = orderApplyMapper.insert(orderApplyDO);
        if (count <= 0) {
            log.error("插入订单退款申请失败");
            throw getAppException("插入订单退款申请失败");
        }
        return true;
    }

    /**
     * 用户调用，根据申请id取消退款申请
     *
     * @param id 退款申请id
     * @return 是否取消成功
     */
    @Override
    public Boolean applyRefundCancelById(Integer id) {
        if (ObjectValidators.isEmpty(id)) {
            throw getAppException("申请编号不能为空");
        }
        CacheUser userInfoDO = currentUserCacheNotNull();
        // 修改申请
        OrderApplyDO orderApplyDO = new OrderApplyDO();
        orderApplyDO.setCancelFlag(OrderApplyDO.CANCEL_FLAG_TRUE);
        orderApplyDO.setRemark("申请人主动取消");
        orderApplyDO.setDealId(userInfoDO.getAccount());
        orderApplyDO.setDealName(userInfoDO.getFirstName() + " " + userInfoDO.getLastName());
        orderApplyDO.setDealTime(LocalDateTime.now());
        orderApplyDO.setDealFlag(OrderApplyDO.DEAL_FLAG_DEAL);
        int count = orderApplyMapper.update(orderApplyDO,
                new LambdaQueryWrapper<OrderApplyDO>()
                        .eq(OrderApplyDO::getId, id)
                        .eq(OrderApplyDO::getDealFlag, OrderApplyDO.DEAL_FLAG_NOT_DEAL)
                        .eq(OrderApplyDO::getCreateUserId, userInfoDO.getAccount()));
        if (count <= 0) {
            throw getAppException("取消申请失败");
        }
        // 修改订单状态
        orderApplyDO = orderApplyMapper.selectById(id);
        if (ObjectValidators.isEmpty(orderApplyDO)) {
            log.error("系统异常，订单数据不存在");
            throw getAppException("系统异常，订单数据不存在");
        }
        if (ObjectValidators.isEmpty(orderApplyDO.getOrderId())) {
            log.error("系统异常，订单申请中订单编号不存在");
            throw getAppException("系统异常，订单数据不存在");
        }
        GoodOrderDO goodOrderDO = new GoodOrderDO();
        goodOrderDO.setId(orderApplyDO.getOrderId());
        goodOrderDO.setState(GoodOrderDO.STATE_TO_TRANS);
        goodOrderMapper.updateById(goodOrderDO);
        return true;
    }

    /**
     * 用户调用，根据订单id取消退款申请
     *
     * @param orderId 订单id
     * @return 是否取消成功
     */
    @Override
    public Boolean applyRefundCancelByOrderId(Integer orderId) {
        if (ObjectValidators.isEmpty(orderId)) {
            throw getAppException("订单编号不能为空");
        }
        CacheUser userInfoDO = currentUserCacheNotNull();
        // 查询申请信息
        List<OrderApplyDO> orderApplyList = orderApplyMapper.selectList(new LambdaQueryWrapper<OrderApplyDO>()
                .eq(OrderApplyDO::getOrderId, orderId)
                .eq(OrderApplyDO::getDealFlag, OrderApplyDO.DEAL_FLAG_NOT_DEAL)
                .eq(OrderApplyDO::getCancelFlag, OrderApplyDO.CANCEL_FLAG_FALSE)
                .eq(OrderApplyDO::getCreateUserId, userInfoDO.getAccount()));
        if (ObjectValidators.isEmpty(orderApplyList)) {
            throw getAppException("订单不存在申请");
        }
        orderApplyList.forEach(item -> {
            Boolean success = this.applyRefundCancelById(item.getId());
            if (!success) {
                throw getAppException("取消退款申请失败：订单编号：" + item.getOrderId());
            }
        });
        return true;
    }

    /**
     * 商家调用，根据orderId对商品进行退款操作
     *
     * @param orderId OrderId
     * @return Boolean 是否成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean refundByOrderId(Integer orderId) {
        if (ObjectValidators.isEmpty(orderId)) {
            throw getAppException("订单编号不能为空");
        }
        CacheStore cacheStore = currentStoreCacheNotNull();
        // 查询订单数据
        GoodOrderDO goodOrderDO = goodOrderMapper.selectOne(
                new LambdaQueryWrapper<GoodOrderDO>()
                        .eq(GoodOrderDO::getStoreId, cacheStore.getId())
                        .eq(GoodOrderDO::getState, GoodOrderDO.STATE_TO_REFUND));
        if (ObjectValidators.isEmpty(goodOrderDO) || ObjectValidators.isEmpty(goodOrderDO.getId())) {
            throw getAppException("订单不存在或不能进行退款操作");
        }

        // 查询订单退款申请数据
        OrderApplyDO orderApplyDO = orderApplyMapper.selectOne(
                new LambdaQueryWrapper<OrderApplyDO>()
                        .eq(OrderApplyDO::getOrderId, goodOrderDO.getId())
                        .eq(OrderApplyDO::getDealFlag, OrderApplyDO.DEAL_FLAG_NOT_DEAL)
                        .eq(OrderApplyDO::getCancelFlag, OrderApplyDO.CANCEL_FLAG_FALSE));
        if (ObjectValidators.isEmpty(orderApplyDO)) {
            log.error("该订单没有退款申请");
            throw getAppException("该订单没有退款申请");
        }

        // 查询订单支付信息
        AlipayNotifyDO alipayNotifyDO = alipayNotifyMapper.selectOne(
                new LambdaQueryWrapper<AlipayNotifyDO>()
                        .eq(AlipayNotifyDO::getOrderId, goodOrderDO.getId()));
        if (ObjectValidators.isEmpty(alipayNotifyDO)) {
            log.error("未支付订单进行退款处理");
            throw getAppException("该订单未支付");
        }

        // 退款
        AlipayNotifyResult result = new AlipayNotifyResult();
        BeanUtils.copyProperties(alipayNotifyDO, result);
        try {
            AlipayClientUtils.tradeRefund(result, (res, response) -> {
                // 修改订单
                goodOrderDO.setState(GoodOrderDO.STATE_REFUNDED)
                        .setEndTime(LocalDateTime.now())
                        .setRemark(String.valueOf(orderApplyDO.getId()));
                goodOrderMapper.updateById(goodOrderDO);
                // 修改退款申请记录
                orderApplyDO.setDealFlag(OrderApplyDO.DEAL_FLAG_DEAL)
                        .setDealTime(LocalDateTime.now())
                        .setDealId(cacheStore.getId())
                        .setDealName(cacheStore.getName())
                        .setRemark("正常退款");
                orderApplyMapper.updateById(orderApplyDO);
            });
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }

        // 退换商品库存
        this.rollbackOrderGoodsCountByIds(Collections.singletonList(orderId));

        return true;
    }

    /**
     * 用户调用，根据订单编号移除订单
     *
     * @param id 订单编号
     * @return 是否移除成功
     */
    @Override
    public Boolean removeOrderUserById(Integer id) {
        if (ObjectValidators.isEmpty(id)) {
            throw getAppException("订单编号不能为空");
        }
        CacheUser userInfoDO = currentUserCacheNotNull();
        GoodOrderDO goodOrderDO = new GoodOrderDO();
        goodOrderDO.setUserFlag(GoodOrderDO.FLAG_FALSE);
        int count = goodOrderMapper.update(goodOrderDO,
                new LambdaUpdateWrapper<GoodOrderDO>()
                        .eq(GoodOrderDO::getId, id)
                        .eq(GoodOrderDO::getUserId, userInfoDO.getAccount())
                        .and(wrapper ->
                                wrapper.or().eq(GoodOrderDO::getState, GoodOrderDO.STATE_CANCEL)
                                        .or().eq(GoodOrderDO::getState, GoodOrderDO.STATE_RECEIVED)
                                        .or().eq(GoodOrderDO::getState, GoodOrderDO.STATE_END)
                                        .or().eq(GoodOrderDO::getState, GoodOrderDO.STATE_REFUNDED)));
        if (count <= 0) {
            throw getAppException("移除订单失败");
        }
        return true;
    }

    /**
     * 店铺调用，根据订单编号移除订单
     *
     * @param id 订单编号
     * @return 是否移除成功
     */
    @Override
    public Boolean removeOrderStoreById(Integer id) {
        if (ObjectValidators.isEmpty(id)) {
            throw getAppException("订单编号不能为空");
        }
        CacheStore cacheStore = currentStoreCacheNotNull();
        GoodOrderDO goodOrderDO = new GoodOrderDO();
        goodOrderDO.setStoreFlag(GoodOrderDO.FLAG_FALSE);
        int count = goodOrderMapper.update(goodOrderDO,
                new LambdaUpdateWrapper<GoodOrderDO>()
                        .eq(GoodOrderDO::getId, id)
                        .eq(GoodOrderDO::getStoreId, cacheStore.getId())
                        .and(wrapper ->
                                wrapper.or().eq(GoodOrderDO::getState, GoodOrderDO.STATE_CANCEL)
                                        .or().eq(GoodOrderDO::getState, GoodOrderDO.STATE_RECEIVED)
                                        .or().eq(GoodOrderDO::getState, GoodOrderDO.STATE_END)
                                        .or().eq(GoodOrderDO::getState, GoodOrderDO.STATE_REFUNDED)));
        if (count <= 0) {
            throw getAppException("移除订单失败");
        }
        return true;
    }

}
